﻿#include <stdint.h>
#include <functional>
#include <vector>
#include <unordered_map>
#include <memory>
#include <iostream>
#include <unistd.h>

// 定时任务类设计
class TimerTask
{
    using TimerTaskHandler_t = std::function<void(void)>; // 定时任务回调函数
    using RemoveUpperManagement_t = std::function<void(void)>; // 移除上层对该定时任务的管理回调函数
private:
    uint64_t _timer_id; // 定时任务唯一标识，与Connection类相互关联
    int _timeout;       // 定时时长
    bool _canceled;     // 定时任务是否被取消，被取消则不执行，默认设置为false
    TimerTaskHandler_t _call_back_handle_task; // 上层提供需要执行的任务函数
    RemoveUpperManagement_t _call_back_remove_timertask; // 上层提供移除上层对定时任务的管理回调函数
public:
    TimerTask(uint64_t timer_id, int timeout)
        :_timer_id(timer_id), _timeout(timeout), _canceled(false)
    {}

    ~TimerTask()
    {
        // 在析构函数进行时，如果定时任务未被取消，执行定时任务；
        if (!_canceled && _call_back_handle_task) _call_back_handle_task();
        //同时，由于定时任务在上层使用shared_ptr管理，该定时任务对象析构时则代表定时任务生命周期已经到达，移除上层对该任务的管理资源
        if (_call_back_remove_timertask) _call_back_remove_timertask();
    }
public:
    // 为外界提供一系列操作接口
    uint64_t Id() { return _timer_id; }
    void Canceled() { _canceled = true; }
    int DelayTime() { return _timeout; }
    void SetTimerTaskHandler(TimerTaskHandler_t call_back) { _call_back_handle_task = call_back; }
    void SetRemoveUpperManagement(RemoveUpperManagement_t call_back) { _call_back_remove_timertask = call_back; }
};

#define MAXCAPACITY 60
// 时间轮类设计——使用数组组织
class TimerWheel
{
    using TimerTaskHandler_t = std::function<void(void)>; // 定时任务回调函数
    using SharedPtr_t = std::shared_ptr<TimerTask>;
    using WeakPtr_t = std::weak_ptr<TimerTask>;
private:
    int _capacity; // 时间轮最大容量
    int _tick; // 滴答指针
    std::vector<std::vector<SharedPtr_t>> _timer_wheel; // 时间轮 
    std::unordered_map<uint64_t, WeakPtr_t> _timertask_management; // 管理时间轮中的所有定时任务，timer_id和weak_ptr作为键值对
    /* 为什么定时任务管理容器中使用weak_ptr，而不是使用shared_ptr呢？ */
    /* shared_ptr内部包含一个计数器，如果使用shared_ptr为shared_ptr赋值，会导致计数器+1，也就无法保证时间轮的中的定时任务在规定的时间内正确清除 */
    /* 而使用weak_ptr接收shared_ptr时不会增加shared_ptr的计数器数值，如此便既保证了对定时任务的管理，也保证了定时任务可以在对象析构的时候正确的执行 */
public:
    TimerWheel()
        :_tick(0), _capacity(MAXCAPACITY), _timer_wheel(_capacity)
    {}
public:
    // 为外界提供的一系列接口

    // 判断定时任务是否存在
    bool IsTimerTaskExist(uint64_t timer_id/*定时任务id*/)
    {
        if (_timertask_management.find(timer_id) != _timertask_management.end()) return true;
        return false;
    }

    // 移除管理容器中的定时任务项，/*设置给Timer，最终定时任务执⾏完毕后从TimerWheel移除TimerTask信息的回调函数*/
    void RemoveTaskFromContainer(uint64_t timer_id/*定时任务id*/)
    {
        auto it = _timertask_management.find(timer_id);
        if (it == _timertask_management.end()) return;
        _timertask_management.erase(it);
    }

    // 添加定时任务：向管理容器和时间轮中同时添加
    void AddTimerTask(TimerTaskHandler_t handle_task/*上层提供的定时任务函数*/, uint64_t timer_id/*定时任务id*/, int timeout/*定时时长*/)
    {
        // 当前时间轮最多支持60s内的定时任务
        if (timeout <= 0 || timeout > 60) return;
        // 当前设计仅支持一个timer_id对应一个定时任务，所以如果定时任务存在则直接返回
        if (IsTimerTaskExist(timer_id)) return;
        // 构造定式任务类的shared_ptr
        SharedPtr_t temp(new TimerTask(timer_id, timeout));
        // 设置定时任务函数，对定时任务的管理回调函数
        temp->SetTimerTaskHandler(handle_task);
        temp->SetRemoveUpperManagement(std::bind(&TimerWheel::RemoveTaskFromContainer, this, timer_id));
        // 加入时间轮相应槽的任务队列中
        int index = (_tick + timeout) % _capacity;
        _timer_wheel[index].emplace_back(temp);
        // 托管给管理容器
        _timertask_management[timer_id] = WeakPtr_t(temp);
    }
    // 刷新定时任务
    void RefreshTimerTask(uint64_t timer_id/*定时任务id*/)
    {
        // 如果定时任务不存在，则直接返回
        if (!IsTimerTaskExist(timer_id)) return;
        // 方式一，不会导致重复计数，因为refresh离开作用域后会自动析构，计数器自动-1
        SharedPtr_t refresh = _timertask_management[timer_id].lock();
        int timeout = refresh->DelayTime();
        // 刷新定时任务在时间轮中的位置
        _timer_wheel[(_tick + timeout) % _capacity].emplace_back(refresh);
    }
    // 取消定时任务
    void CancelTimerTask(uint64_t timer_id)
    {
        if (!IsTimerTaskExist(timer_id)) return;
        WeakPtr_t temp = _timertask_management[timer_id];
        temp.lock()->Canceled();
    }
    /*每滴答⼀次被执⾏_tick++就会向后⾛⼀步，⾛到哪⾥，释放哪⾥的定时器，也就是执⾏哪⾥的定时任务*/
    void RunOnTimeTask()
    {
        _tick = (_tick + 1) % _capacity;
        _timer_wheel[_tick].clear();

    }
};

class Connection {
private:
    uint64_t _timer_id;
public:
    Connection(uint64_t timer_id) : _timer_id(timer_id) { std::cout << "Connection 构造!\n" << std::endl; }
    ~Connection() { std::cout << "Connection 析构!\n" << std::endl; }
    void del() { delete this; }
};

//int main()
//{
//    // 简单示范：
//
//    // 构造一个时间轮
//    TimerWheel wheel;
//    // 创建一个连接
//    Connection* conn = new Connection(10086);
//    // 向时间轮中添加一个5秒后的定时任务
//    wheel.AddTimerTask(std::bind(&Connection::del, conn), 10086, 5);
//    for (int i = 1; i > 0; i++)
//    {
//        printf("这是第 %d 秒......\n", i);
//        sleep(1);
//        wheel.RunOnTimeTask();
//        if (i == 3) {
//            // 取消定时任务
//            //wheel.CancelTimerTask(10086);
//            // 刷新定时任务的时间
//            wheel.RefreshTimerTask(10086); // 应该在8s后析构
//        }
//    }
//    return 0;
//}